#include "droppablewidget.h"
#include "flattingwindow.h"
#include "ui_droppablewidget.h"

#include <QStatusBar>
#include <QPlainTextEdit>
#include <QMimeData>
#include <QSplitter>
#include <QTimer>

#include "dropmanager.h"
#include "dragabletab.h"
#include "tabsscrollarea.h"
#include "toolutils.h"

DroppableWidget::DroppableWidget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::DroppableWidget)
{
    ui->setupUi(this);
    this->setAcceptDrops(true);
    // auto content = new QPlainTextEdit(this);
    // content->setObjectName("无标题");
    // auto pages = AddPagesWidget("无标题", content, this);
    // ui->mainLayout->addWidget(pages);
    // pages->setObjectName("normal");
    // mRoot = new WidgetTree(pages, WidgetTree::PAGE);

    // auto view = new ImageEditor("C:\\Users\\admin\\Pictures\\preview_png.png", this);
    // view->setAlignment(Qt::AlignCenter);
    // view->setAcceptDrops(false);

    // AddPageToFocusPagesWidget("preview_png.png", view, DragableTab::TabType::IMAGE);


    // auto music = new SVideoWidget(R"(C:\Users\admin\Music\陈奕迅 - 岁月如歌+兄妹(Live).mp3)", this);
    // music->setAcceptDrops(false);
    // AddPageToFocusPagesWidget("陈奕迅 - 岁月如歌+兄妹(Live).mp3", music, DragableTab::TabType::MUSIC);

    // connect(this, &DroppableWidget::dropIn, this, &DroppableWidget::TabDropInWidgetSlots);
}

DroppableWidget::~DroppableWidget()
{
    delete ui;
}

int DroppableWidget::Id()
{
    return mId;
}

void DroppableWidget::SetId(int id)
{
    mId = id;
}

void DroppableWidget::AddPageToFocusPagesWidget(DragableTab *tab, QWidget *widget)
{
    if (mFocusPagesWidget == nullptr) {
        AddPagesWidget(tab, widget, this);
        return;
    }
    mFocusPagesWidget->AddPage(tab, widget);
}

void DroppableWidget::AddPageToFocusPagesWidget(QString titleLabel, QWidget *widget, DragableTab::TabType tabType)
{
    if (mFocusPagesWidget == nullptr) {
        auto pages = AddPagesWidget(titleLabel, widget, this);
        ui->mainLayout->addWidget(pages);
        mRoot = new WidgetTree(pages, WidgetTree::PAGE);
        return;
    }
    widget->setObjectName(titleLabel);
    mFocusPagesWidget->AddPage(titleLabel, widget, tabType);
}

void DroppableWidget::RemoveFocusPage()
{
    auto page = mFocusPagesWidget->RemovePage(mFocusPage.first);
    page.first->close();
    page.second->close();
    delete page.first;
    delete page.second;
}

PagesWidget* DroppableWidget::FindPagesById(int id)
{
    if (mRoot == nullptr) {
        return nullptr;
    }

    if (mRoot->WidgetType() == WidgetTree::PAGE
        && qobject_cast<PagesWidget*>(mRoot->Widget())->Id().second == id) {
        return qobject_cast<PagesWidget*>(mRoot->Widget());
    }

    WidgetTree* areaChild = mRoot;
    auto treeChildren = areaChild->Children();
    while (!treeChildren.empty()) {
        auto child = treeChildren.front();
        treeChildren.pop_front();
        treeChildren.append(child->Children());
        if (child->WidgetType() != WidgetTree::PAGE) {
            continue;
        }

        auto pages = qobject_cast<PagesWidget*>(child->Widget());
        if (pages->Id().second != id) {
            continue;
        }
        qDebug("DroppableWidget::FindPagesById, pagesId=(%d, %d)", pages->Id().first, pages->Id().second);
        return pages;
    }
    return nullptr;
}

bool DroppableWidget::IsContainPages(PagesWidget* pagesWidget)
{
    if (mRoot == nullptr || pagesWidget == nullptr) {
        return false;
    }

    if (mRoot->WidgetType() == WidgetTree::PAGE
        && mRoot->Widget() == pagesWidget) {
        return true;
    }

    WidgetTree* areaChild = mRoot;
    auto treeChildren = areaChild->Children();
    while (!treeChildren.empty()) {
        auto child = treeChildren.front();
        treeChildren.pop_front();
        treeChildren.append(child->Children());
        if (child->WidgetType() != WidgetTree::PAGE) {
            continue;
        }
        if (child->Widget() != pagesWidget) {
            continue;
        }
        return true;
    }
    return false;
}

// discard...
void DroppableWidget::dragEnterEvent(QDragEnterEvent *event)
{
    // qDebug() << "DropableWidget::dragEnterEvent";
    if (event->mimeData()->hasFormat("application/tab-data") || event->mimeData()->hasFormat("application/tabsScrollArea-data")) {
        event->acceptProposedAction();
    }
    QWidget::dragEnterEvent(event);
}


// discard...
// void DroppableWidget::dragMoveEvent(QDragMoveEvent *event)
// {
//     if (event->mimeData()->hasFormat("application/tab-data")) {
//         event->acceptProposedAction();
//     }
//     QWidget::dragMoveEvent(event);
// }


// discard...
// void DroppableWidget::dragLeaveEvent(QDragLeaveEvent *event)
// {
//     // qDebug() << "DropableWidget::dragLeaveEvent";
//     event->ignore();
//     QWidget::dragLeaveEvent(event);
// }

std::pair<DragableTab*, QWidget*> DroppableWidget::FocusPage()
{
    return mFocusPage;
}

void DroppableWidget::ChangeFocusPage(PagesWidget* pagesWidget)
{
    auto oldPagesWidget = mFocusPagesWidget;
    mFocusPagesWidget = pagesWidget;
    auto oldPage = mFocusPage;
    mFocusPage = pagesWidget->CurrentPage();
    qDebug("DroppableWidget::ChangeFocusPage, page=%s", mFocusPage.first->TitleLabel()->text().toStdString().c_str());

    if (mFocusPage.first != nullptr) {
        mFocusPage.first->setStyleSheet(ToolUtils::ReadStyleSheet(":/qss/focusTabUi.qss"));
    }

    if (oldPagesWidget != nullptr && oldPage.first != nullptr && oldPagesWidget!= mFocusPagesWidget && oldPagesWidget->CurrentPage().first == oldPage.first)
    {
        oldPage.first->setStyleSheet(ToolUtils::ReadStyleSheet(":/qss/currentTabUi.qss"));
    }

    // 确保窗口被激活
    if (!this->isActiveWindow()) {
        this->activateWindow();
    }

    // ##延迟设置焦点，确保没有其他控件抢回焦点
    QTimer::singleShot(0, this, [this]() {
        if (mFocusPage.second == nullptr) {
            return;
        }
        mFocusPage.second->setFocus();
        emit FocusPageChanged();
    });
}

// TODO: 疑难问题，如何准确设置focus --> 已解决，采用计时器延迟转移焦点
void DroppableWidget::ChangeFocusPagesWidget(const QWidget* content)
{
    const auto tabsScrollArea = qobject_cast<TabsScrollArea*>(sender());
    if (tabsScrollArea == nullptr) {
        return;
    }
    ChangeFocusPage(tabsScrollArea->ParentPagesWidget());
}

void DroppableWidget::AddPagesWidget(PagesWidget* pagesWidget)
{
    // 这里需要判断一下是不是内部移动
    // 如果要移动的话，必须把内部的scroll和tab的id都更新一下
    pagesWidget->setParent(this);
    pagesWidget->SetParentDroppableWidget(this);
    if (pagesWidget == nullptr || IsContainPages(pagesWidget)) {
        qDebug() << "DroppableWidget::AddPagesWidget, pagesWidget == nullptr || IsContainPages(pagesWidget) ";
        return;
    }
    pagesWidget->SetId(mId, mMaxPagesId++);
    // disconnect
    pagesWidget->disconnect(SIGNAL(closed()));
    pagesWidget->GetTabsScrollArea()->disconnect(SIGNAL(currentPageChanged(QWidget*)));
    pagesWidget->GetTabsScrollArea()->disconnect(SIGNAL(NeedToFlatPage(int)));
    pagesWidget->GetTabsScrollArea()->disconnect(SIGNAL(NeedToFlatAllPages()));

    // connect
    connect(pagesWidget, &PagesWidget::closed, this, &DroppableWidget::RemovePage, Qt::DirectConnection);
    connect(pagesWidget->GetTabsScrollArea(), &TabsScrollArea::currentPageChanged, this, &DroppableWidget::ChangeFocusPagesWidget, Qt::DirectConnection);
    connect(pagesWidget->GetTabsScrollArea(), &TabsScrollArea::NeedToFlatPage, this, &DroppableWidget::FlatPage);
    connect(pagesWidget->GetTabsScrollArea(), &TabsScrollArea::NeedToFlatAllPages, this, &DroppableWidget::FlatPages);

    if (mRoot == nullptr) {
        // qDebug() << "DroppableWidget::AddPagesWidget, mRoot == nullptr";
        mRoot = new WidgetTree(pagesWidget, WidgetTree::PAGE);
        mFocusPagesWidget = pagesWidget;
        mFocusPage = pagesWidget->CurrentPage();
        ui->mainLayout->addWidget(pagesWidget);
    }
}

PagesWidget* DroppableWidget::AddPagesWidget(QString tabLabel, QWidget* content, QWidget* parent)
{
    // TODO: 需要更新一下函数，新增一个type
    auto tab = new DragableTab(tabLabel, DragableTab::TabType::TEXT);
    return AddPagesWidget(tab, content, parent);
}

PagesWidget* DroppableWidget::AddPagesWidget(DragableTab* tab, QWidget* content, QWidget* parent)
{
    auto pagesWidget = new PagesWidget(parent);
    AddPagesWidget(pagesWidget);
    pagesWidget->AddPage(tab, content);
    return pagesWidget;
}

void DroppableWidget::RemovePagesWidget(PagesWidget* closePagesWidget)
{
    auto closeNode = mRoot->findChild(closePagesWidget);
    auto parentNode = closeNode->Parent();
    if (parentNode == nullptr) {
        // 如果该节点的父节点都为空了，说明是最后一个节点，所有page都被关闭了
        qDebug() << "DroppableWidget::removePage, AllPagesClosed";
        mRoot = nullptr;
        closeNode->deleteLater();
        emit AllPagesClosed();
        return;
    }

    // 移除该container上面的page节点
    parentNode->removeChild(closeNode);
    closePagesWidget->SetParentDroppableWidget(nullptr);

    // focusWidget的改变
    WidgetTree* areaChild = mRoot;
    auto treeChildren = areaChild->Children();
    while (!treeChildren.empty()) {
        auto child = treeChildren.front();
        treeChildren.pop_front();
        treeChildren.append(child->Children());
        if (child->WidgetType() != WidgetTree::PAGE) {
            continue;
        }
        auto pages = qobject_cast<PagesWidget*>(child->Widget());
        ChangeFocusPage(pages);
        break;
    }

    if (parentNode->Children().count() > 1) {
        // 孩子节点大于1，说明至少还有两个孩子使用该layout
        return;
    }

    if (parentNode->Parent() == nullptr) {
        // 孩子节点为1，且整个droppableWidget只有一个pagesWidget
        // 将container节点的第一个节点，即最后一个pagesWidget作为mRoot
        mRoot = parentNode->Children().first();
        // layout上面replace掉当前container的widget位置
        ui->mainLayout->replaceWidget(parentNode->Widget(), mRoot->Widget());
        // 删除将即将删除的container的子节点请掉，并清除内存
        parentNode->Clear();
        parentNode->Widget()->close();
        parentNode->Splitter()->close();
        // closePagesWidget->deleteLater();
        closeNode->deleteLater();
        parentNode->deleteLater();
        return;
    }

    // 这里涉及到页面显示的改变
    auto splitter = parentNode->Parent()->Splitter();
    auto child = parentNode->Children().first();
    parentNode->Clear();
    splitter->replaceWidget(splitter->indexOf(parentNode->Widget()), child->Widget());
    parentNode->Parent()->addChild(child);
    parentNode->Parent()->removeChild(parentNode);
    parentNode->Widget()->close();
    // closePagesWidget->deleteLater();
    closeNode->deleteLater();
    parentNode->deleteLater();
}

void DroppableWidget::RemovePage()
{
    auto closePagesWidget = qobject_cast<PagesWidget*>(sender());
    if (closePagesWidget == nullptr) {
        return;
    }
    RemovePagesWidget(closePagesWidget);
    closePagesWidget->deleteLater();
    // mRoot->PrintTree();
}

bool DroppableWidget::PagesDropIn(QPoint dropPos, std::tuple<int, int, int> dragIndex)
{
    // 需要先remove、在add才符合逻辑，特别是在同一个droppableWidget里面
    // 通过循环找到该落点区域, 落点区域必为pagesWidget(假设，有极小概率落到QSplitter上面，后续新增), 并计算出该增加page的方向
    QWidget* areaWidget = mRoot->Widget();
    WidgetTree* areaChild = mRoot;
    auto treeChildren = areaChild->Children();
    while (!treeChildren.empty()) {
        qDebug("areaChild=%s", areaWidget->metaObject()->className());
        foreach (const auto child, treeChildren) {
            QPoint pos = child->Widget()->parentWidget()->mapToGlobal(child->Widget()->pos());
            QSize size = child->Widget()->size();
            if (dropPos.x() >= pos.x() && dropPos.x() <= pos.x() + size.width()
                && dropPos.y() >= pos.y() && dropPos.y() <= pos.y() + size.height()) {
                areaWidget = child->Widget();
                areaChild = child;
                break;
            }
        }
        treeChildren = areaChild->Children();
    }

    auto dropPagesWidget = qobject_cast<PagesWidget*>(areaWidget);
    if (dropPagesWidget == nullptr || areaChild == nullptr) {
        qDebug() << "DroppableWidget::PagesDropIn, dropPagesWidget == nullptr";
        return false;
    }

    auto pos = dropPagesWidget->parentWidget()->mapToGlobal(dropPagesWidget->pos());
    auto size = dropPagesWidget->size();
    auto centralPos = pos + QPoint(size.width() / 2, size.height() / 2);
    int direction = computeDirection(dropPos, centralPos);
    qDebug("areaChild=%s, pos=(%d, %d), centralPos=(%d, %d), size=(%d, %d), direciton=%d",
           dropPagesWidget->metaObject()->className(), pos.x(), pos.y(), centralPos.x(), centralPos.y(), size.width(), size.height(), direction);

    // 添加pagesWidget
    // 这里包含了drop 一整个pagesWidget 和 单独的tab
    PagesWidget* dragPagesWidget = nullptr;
    if (std::get<2>(dragIndex) == -1) {
        dragPagesWidget = DropManager::GetInstance()->FindPagesWidget(std::get<0>(dragIndex), std::get<1>(dragIndex));
        if (dragPagesWidget == dropPagesWidget) {
            qDebug() << "DroppableWidget::PagesDropIn, dragPagesWidget == dropPagesWidget";
            return false;
        }
        // 所属的widget先remove掉dropPagesWidget，再把它插入到dropWidgets所在的方向
        const auto parentdroppabelWidget = dragPagesWidget->ParentDroppableWidget();
        parentdroppabelWidget->RemovePagesWidget(dragPagesWidget);
        AddPagesWidget(dragPagesWidget);
    } else {
        auto page = DropManager::GetInstance()->FindSinglePage(
            std::get<0>(dragIndex), std::get<1>(dragIndex), std::get<2>(dragIndex));
        if (page.first == nullptr || page.second == nullptr) {
            qDebug() << "DroppableWidget::PagesDropIn, page.first == nullptr || page.second == nullptr";
            return false;
        }
        dragPagesWidget = AddPagesWidget(page.first, page.second, this);
    }

    if (dragPagesWidget == nullptr) {
        qDebug() << "DroppableWidget::PagesDropIn, dragPagesWidget == nullptr";
        return false;
    }


    // 确定添加方向和layout方向是否相同，来判断是否新增container、splitter、layout
    const auto parentContainer = areaChild->Parent() ? areaChild->Parent()->Widget() : nullptr;
    bool isNeedToAddContainer = true;
    if (parentContainer != nullptr && parentContainer->layout() != nullptr && qobject_cast<QBoxLayout*>(parentContainer->layout()) != nullptr) {
        const QBoxLayout::Direction layoutDirection = qobject_cast<QBoxLayout*>(parentContainer->layout())->direction();
        qDebug() << "dropDirection=" << direction << ", layoutDirection=" << layoutDirection;
        if (((layoutDirection == QBoxLayout::Direction::LeftToRight || layoutDirection == QBoxLayout::Direction::LeftToRight)
                && (direction == 0 || direction == 2))
            || ((layoutDirection == QBoxLayout::Direction::BottomToTop || layoutDirection == QBoxLayout::Direction::TopToBottom)
                && (direction == 1 || direction == 3))) {
            isNeedToAddContainer = false;
        }
    }

    if (!isNeedToAddContainer) {
        auto parentSplitterNode = areaChild->Parent();
        auto pagesNode = new WidgetTree(dragPagesWidget, WidgetTree::PAGE, 0, parentSplitterNode);
        parentSplitterNode->addChild(pagesNode);
        const auto splitter = areaChild->Parent()->Splitter();
        const int index = splitter->indexOf(dropPagesWidget);
        if (direction == 0 || direction == 3) {
            splitter->insertWidget(index + 1, dragPagesWidget);
        }
        if (direction == 1 || direction == 2) {
            splitter->insertWidget(index, dragPagesWidget);
        }
        qDebug() << "isNeedToAddContainer is false";
        // mRoot->PrintTree();
        return true;
    }

    // 增加widget和对应的layout
    // container
    auto container = new QWidget(this);

    // splitter
    auto splitter = new QSplitter(container);
    // 默认不能折叠，以后看看适配一下
    splitter->setChildrenCollapsible(false);

    // direction
    QLayout* layout = nullptr;
    if (direction == 0 || direction == 2) {
        //layout
        layout = new QHBoxLayout(container);
        splitter->setOrientation(Qt::Orientation::Horizontal);
    }

    if (direction == 1 || direction == 3) {
        //layout
        layout = new QVBoxLayout(container);
        splitter->setOrientation(Qt::Orientation::Vertical);
    }

    auto parentNode = areaChild->Parent();
    auto splitterNode = new WidgetTree(container, WidgetTree::SPLITTER, splitter, parentNode);
    auto pagesNode = new WidgetTree(dragPagesWidget, WidgetTree::PAGE, nullptr, splitterNode);

    if (parentNode != nullptr) {
        parentNode->addChild(splitterNode);
        parentNode->removeChild(areaChild);
        // TODO: 这里面应该还有页面相关的操作
        auto index = parentNode->Splitter()->indexOf(dropPagesWidget);
        parentNode->Splitter()->replaceWidget(index, container);
    } else {
        ui->mainLayout->addWidget(container);
        ui->mainLayout->removeWidget(dropPagesWidget);
        mRoot = splitterNode;
    }

    splitterNode->addChild(pagesNode);
    splitterNode->addChild(areaChild);

    layout->setContentsMargins(0, 0, 0, 0);
    layout->setSpacing(0);
    layout->addWidget(splitter);
    if (direction == 0 || direction == 3) {
        splitter->addWidget(dropPagesWidget);
        splitter->addWidget(dragPagesWidget);
    }
    if (direction == 1 || direction == 2) {
        splitter->addWidget(dragPagesWidget);
        splitter->addWidget(dropPagesWidget);
    }
    mRoot->PrintTree();
    return true;
}

int DroppableWidget::computeDirection(const QPoint& dropPos, const QPoint& centralPos)
{
    // 根据45°、135°、225°、315°、45°划分为四个区域，来区分所在方向是上、下、左、右
    auto angle = std::atan2(centralPos.y() - dropPos.y(), dropPos.x() - centralPos.x());
    int angle_degrees = static_cast<int>(angle * (180.0 / M_PI) + 360) % 360;
    // qDebug("MainWindow::TabDropInWidgetSlots, angle_degrees=%d", angle_degrees);;
    // 根据角度划分区域
    if (angle_degrees >= 315 || angle_degrees < 45) {
        // qDebug() << "Right";
        return 0;
    } else if (angle_degrees >= 45 && angle_degrees < 135) {
        // qDebug() << "Up";
        return 1;
    } else if (angle_degrees >= 135 && angle_degrees < 225) {
        // qDebug() << "Left";
        return 2;
    } else if (angle_degrees >= 225 && angle_degrees < 315) {
        // qDebug() << "down";
        return 3;
    }
    return 0;
}

// TODO:
// 需要重新定义一个 QWidget，如何把statusBar搞进去 <仿照Widget>
void DroppableWidget::FlatPage(int index)
{
    qDebug() << "DroppableWidget::FlatPage";
    // 先删除window
    auto tabsScrollArea = qobject_cast<TabsScrollArea*>(sender());
    auto page = tabsScrollArea->RemovePage(index);
    const auto flattingWindow = new FlattingWindow(page);
    // 将窗口move到光标所在的位置，并显示
    flattingWindow->move(QCursor::pos());
    flattingWindow->show();
}

void DroppableWidget::FlatPages()
{
    qDebug() << "DroppableWidget::FlatPages";
    auto tabsScrollArea = qobject_cast<TabsScrollArea*>(sender());
    auto pagesWidget = tabsScrollArea->ParentPagesWidget();
    this->RemovePagesWidget(pagesWidget);
    auto flattingWindow = new FlattingWindow(pagesWidget);
    // 将窗口move到光标所在的位置，并显示
    flattingWindow->move(QCursor::pos());
    flattingWindow->show();
}
